"""
A simple logging module, with easy configuration, labeling and filtering.
"""
import sys
import os
import thread
import time
from traceback import format_stack, format_exception


stdlogdev = sys.stdout
errlogdev = sys.stderr
show_label = True
show_date = False
show_time = True
show_source = False
show_pid = False
show_tid = False
show_stack = False
filter_labels = set()
filter_sources = set()


def log(dev, label, msg, args = (), source = None):
    if label in filter_labels or source in filter_sources:
        return
    items = []
    if show_label:
        items.append(str(label))
    if show_source and source:
        items.append("(%s)" % (source,))
    if show_date:
        items.append(time.strftime("%Y.%m.%d"))
    if show_time:
        items.append(time.strftime("%H:%M:%S"))
    if show_pid:
        items.append("pid=%5d" % (os.getpid(),))
    if show_tid:
        items.append("tid=%5d" % (thread.get_ident(),))
    if args:
        msg %= args
    if items:
        banner = "[" + " ".join(items) + "] "
    else:
        banner = ""
    dev.write(banner + msg + "\n")
    dev.flush()

def debug(msg, *args, **kwargs):
    withstack = kwargs.pop("show_stack", show_stack)
    if args:
        msg %= args
    if withstack:
        msg += "\n" + "".join(format_stack()[:-1])
    log(stdlogdev, "DEBUG", msg, **kwargs)

def info(msg, *args, **kwargs):
    log(stdlogdev, "INFO", msg, args, **kwargs)

def warn(msg, *args, **kwargs):
    log(stdlogdev, "WARNING", msg, args, **kwargs)

def error(msg, *args, **kwargs):
    log(errlogdev, "ERROR", msg, args, **kwargs)

def traceback(**kwargs):
    msg = "".join(format_exception(*sys.exc_info()))
    log(errlogdev, "TRACEBACK", msg, **kwargs)

def fatal(msg, *args, **kwargs):
    log(errlogdev, "FATAL", msg, args, **kwargs)
    sys.exit()


if __name__ == "__main__":
    info("hi %s", "world")          # [INFO 17:37:58] hi world
    show_date = True
    info("hi %s", "world")          # [INFO 2008.01.18 17:37:58] hi world
    filter_labels.add("INFO")       
    info("bar")                     # <no output>
    
    def f():
        g()
    def g():
        h()
    def h():
       debug("foo")
    
    f()                             # [DEBUG 2008.01.18 17:37:58] foo
    
    show_stack = True
    f()
    #[DEBUG 2008.01.18 17:40:06] foo
    #  File "D:\projects\ganges\log.py", line 92, in <module>
    #    f()
    #  File "D:\projects\ganges\log.py", line 83, in f
    #    g()
    #  File "D:\projects\ganges\log.py", line 85, in g
    #    h()
    #  File "D:\projects\ganges\log.py", line 87, in h
    #    debug("foo")
    
    show_date = False
    
    try:
       1/0
    except:
       traceback()
       # [TRACEBACK 17:37:58] Traceback (most recent call last):
       #   File "D:\projects\ganges\log.py", line 92, in <module>
       #     1/0
       # ZeroDivisionError: integer division or modulo by zero











